package org.vison.wonfu.framework.dao.p6spy;


import com.p6spy.engine.common.*;
import com.p6spy.engine.event.JdbcEventListener;
import lombok.extern.slf4j.Slf4j;

import java.sql.ResultSet;
import java.sql.SQLException;


@Slf4j
public class P6spyListener extends JdbcEventListener {

    private static final ThreadLocal<Integer> sqlCountPerRequest = ThreadLocal.withInitial(() -> 0);

    public static int getSqlCountForCurrentRequest() {
        return sqlCountPerRequest.get();
    }

    public static void resetSqlCountForCurrentRequest() {
        sqlCountPerRequest.remove();
    }


    @Override
    public void onAfterGetConnection(ConnectionInformation connectionInformation, SQLException e) {
//        log.info("get connection");
    }

    @Override
    public void onAfterExecuteQuery(StatementInformation statementInformation, long timeElapsedNanos, String sql, SQLException e) {
//        log.info("execute query... {}", statementInformation.getSqlWithValues());
    }

    @Override
    public void onBeforeAddBatch(PreparedStatementInformation statementInformation) {
        super.onBeforeAddBatch(statementInformation);
    }

    @Override
    public void onAfterAddBatch(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
        super.onAfterAddBatch(statementInformation, timeElapsedNanos, e);
    }

    @Override
    public void onBeforeAddBatch(StatementInformation statementInformation, String sql) {
        super.onBeforeAddBatch(statementInformation, sql);
    }

    @Override
    public void onAfterAddBatch(StatementInformation statementInformation, long timeElapsedNanos, String sql, SQLException e) {
        super.onAfterAddBatch(statementInformation, timeElapsedNanos, sql, e);
    }

    @Override
    public void onBeforeExecute(PreparedStatementInformation statementInformation) {
//        log.info("onBeforeExecute");
    }

    @Override
    public void onAfterExecute(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {

        Long timeElapsedMilSecond = timeElapsedNanos / (1000 * 1000);
        String singleLineSql = P6Util.singleLine(statementInformation.getSqlWithValues());
        singleLineSql = singleLineSql.replaceAll(" +", " ");
        String rowsMessage = "";
        try {
            if (e != null) {
                throw e;
            }
            String upperSingleLineSql = singleLineSql.toUpperCase();
            if (upperSingleLineSql.startsWith("SELECT")) {
                // execute、executeQuery和executeUpdate 不同的api对结果集的处理方式会不同
                int selectRows = 0;
                ResultSet resultSet = statementInformation.getStatement().getResultSet();
                resultSet.last();
                selectRows = resultSet.getRow();
                resultSet.absolute(0);
                rowsMessage = String.format("结果行数 %d", selectRows);
            }

            if (upperSingleLineSql.startsWith("UPDATE") || upperSingleLineSql.startsWith("DELETE") ||
                    upperSingleLineSql.startsWith("INSERT")) {
                Integer updateRows = statementInformation.getStatement().getUpdateCount();
                rowsMessage = String.format("影响行数 %d", updateRows);
            }
        } catch (SQLException ex) {
            rowsMessage = "发生错误" + ex.getMessage();

        } catch (Exception ex) {
            log.error("onAfterExecute 发生错误 ", ex);
        }
        log.info("onAfterExecute 执行sql {} 耗时 {} ms {}", singleLineSql, timeElapsedMilSecond, rowsMessage);
        sqlCountPerRequest.set(sqlCountPerRequest.get() + 1);
    }

    @Override
    public void onBeforeExecute(StatementInformation statementInformation, String sql) {
        log.info("onBeforeExecute");
    }

    @Override
    public void onBeforeExecuteBatch(StatementInformation statementInformation) {
        log.info("onBeforeExecuteBatch");
    }

    @Override
    public void onAfterExecuteBatch(StatementInformation statementInformation, long timeElapsedNanos, int[] updateCounts, SQLException e) {
//        log.info("onAfterExecuteBatch");
    }

    @Override
    public void onBeforeExecuteUpdate(PreparedStatementInformation statementInformation) {
//        log.info("onBeforeExecuteUpdate");
    }

    @Override
    public void onBeforeExecuteUpdate(StatementInformation statementInformation, String sql) {
//        log.info("onBeforeExecuteUpdate");
    }

    @Override
    public void onAfterExecuteUpdate(StatementInformation statementInformation, long timeElapsedNanos, String sql, int rowCount, SQLException e) {
//        log.info("onAfterExecuteUpdate");
    }

    @Override
    public void onBeforeExecuteQuery(PreparedStatementInformation statementInformation) {
//        log.info("onBeforeExecuteQuery");
    }

    @Override
    public void onAfterExecuteQuery(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
//        log.info("onAfterExecuteQuery");
    }

    @Override
    public void onAfterPreparedStatementSet(PreparedStatementInformation statementInformation, int parameterIndex, Object value, SQLException e) {
//        log.info("onAfterPreparedStatementSet");
    }

    @Override
    public void onAfterCallableStatementSet(CallableStatementInformation statementInformation, String parameterName, Object value, SQLException e) {
//        log.info("onAfterCallableStatementSet");
    }

    @Override
    public void onAfterGetResultSet(StatementInformation statementInformation, long timeElapsedNanos, SQLException e) {

    }

    @Override
    public void onBeforeResultSetNext(ResultSetInformation resultSetInformation) {
//        log.info("onBeforeResultSetNext");
    }

    @Override
    public void onAfterResultSetNext(ResultSetInformation resultSetInformation, long timeElapsedNanos, boolean hasNext, SQLException e) {
//        log.info("onAfterResultSetNext");
    }

    @Override
    public void onAfterResultSetClose(ResultSetInformation resultSetInformation, SQLException e) {
//        log.info("onAfterResultSetClose row");
    }

    @Override
    public void onAfterResultSetGet(ResultSetInformation resultSetInformation, String columnLabel, Object value, SQLException e) {
//        log.info("onAfterResultSetGet");
    }

    @Override
    public void onAfterResultSetGet(ResultSetInformation resultSetInformation, int columnIndex, Object value, SQLException e) {
//        log.info("onAfterResultSetGet");
    }

    @Override
    public void onBeforeCommit(ConnectionInformation connectionInformation) {
//        log.info("onBeforeCommit");
    }

    @Override
    public void onAfterCommit(ConnectionInformation connectionInformation, long timeElapsedNanos, SQLException e) {
//        log.info("onAfterCommit");
    }

    @Override
    public void onAfterConnectionClose(ConnectionInformation connectionInformation, SQLException e) {
//        log.info("onAfterConnectionClose");
    }

    @Override
    public void onBeforeRollback(ConnectionInformation connectionInformation) {
//        log.info("onBeforeRollback");
    }

    @Override
    public void onAfterRollback(ConnectionInformation connectionInformation, long timeElapsedNanos, SQLException e) {
//        log.info("onAfterRollback");
    }

    @Override
    public void onAfterStatementClose(StatementInformation statementInformation, SQLException e) {
//        log.info("onAfterStatementClose");
    }

    @Override
    public void onBeforeSetAutoCommit(ConnectionInformation connectionInformation, boolean newAutoCommit, boolean currentAutoCommit) {
//        log.info("onBeforeSetAutoCommit");
    }

    @Override
    public void onAfterSetAutoCommit(ConnectionInformation connectionInformation, boolean newAutoCommit, boolean oldAutoCommit, SQLException e) {
//        log.info("onAfterSetAutoCommit");
    }

    @Override
    public void onAfterExecuteUpdate(PreparedStatementInformation statementInformation, long timeElapsedNanos, int rowCount, SQLException e) {
//        log.info("execute update..{}", statementInformation.getSqlWithValues());
    }

    @Override
    public void onBeforeExecuteQuery(StatementInformation statementInformation, String sql) {
//        log.info("execute.. {}", statementInformation.getSqlWithValues());
    }
}
